package com.ms.orm.conditions;

import com.ms.common.util.CollectionUtils;
import com.ms.common.util.StringUtils;
import com.ms.orm.conditions.segments.MergeSegments;
import com.ms.orm.conditions.segments.NormalSegmentList;
import com.ms.orm.constants.Constants;
import com.ms.orm.constants.StringPool;
import com.ms.orm.context.DefaultLittleOrmContext;
import com.ms.orm.meta.EntityAndTableInfo;
import com.ms.orm.meta.PropertyAndColumnInfo;
import com.ms.orm.util.MetaDataOperator;
import java.util.Objects;

/**
 * @author
 * 条件构造抽象类
 */
public abstract class Wrapper<T> implements ISqlSegment {


    /**
     * 实体对象（子类实现）
     * @return 泛型 T
     */
    public abstract T getEntity();

    /**
     * 获取 数据库表属性字段，比如 id,name,age,gender等
     * 查询用户指定的列
     * @return
     */
    public String getSqlSelect() {
        return null;
    }

    /**
     * 获取 最终执行 sql，并且有占位符 ? ,传到jdbcTemplate 还需要传入参数
     * @return
     */
    public String getFinalSql() {
        return null;
    }

    /**
     *  获取更新字段Sql片段 ：比如SQL 更新字段内容，例如：name='1', age=2
     * @return
     */
    public String getSqlSet() {
        return null;
    }


    /**
     * 获取 sql 注释
     * @return
     */
    public String getSqlComment() {
        return null;
    }

    /**
     * SQL起始语句: 比如？
     * @return
     */
    public String getSqlFirst() {
        return null;
    }


    /**
     * 获取 MergeSegments ，包含sql查询语句中各个部分
     * @return
     */
    public abstract MergeSegments getExpression();

    /**
     * 获取自定义SQL 简化自定义XML复杂情况
     * <p>
     * 使用方法: `select xxx from table` + ${ew.customSqlSegment}
     * <p>
     * 注意事项:
     * 1. 逻辑删除需要自己拼接条件 (之前自定义也同样)
     * 2. 不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)
     * 3. 用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)
     * 4. ew是wrapper定义别名,不能使用其他的替换
     */
    public String getCustomSqlSegment() {
        //1、获取查询sql的各个部分 集合对象
        MergeSegments expression = getExpression();
        if (Objects.nonNull(expression)) {
            //2、获取普通部分
            NormalSegmentList normal = expression.getNormal();
            //3、获取where 之后的完整 查询sql
            String sqlSegment = getSqlSegment();
            if (StringUtils.isNotBlank(sqlSegment)) {
                if (normal.isEmpty()) {
                    //如果 where 之后的完整  部分不为空，normal为null，直接返回sqlSegment，不用拼接where条件
                    return sqlSegment;
                } else {
                    //拼接where条件
                    return Constants.WHERE + StringPool.SPACE + sqlSegment;
                }
            }
        }
        return StringPool.EMPTY;
    }

    /**
     * 查询条件为空(包含entity)
     */
    public boolean isEmptyOfWhere() {
        return isEmptyOfNormal() && isEmptyOfEntity();
    }

    /**
     * 查询条件不为空(包含entity)
     */
    public boolean nonEmptyOfWhere() {
        return !isEmptyOfWhere();
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isEmptyOfNormal() {
        return CollectionUtils.isEmpty(getExpression().getNormal());
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean nonEmptyOfNormal() {
        return !isEmptyOfNormal();
    }

    /**
     * 深层实体判断属性
     *
     * @return true 不为空
     */
    public boolean nonEmptyOfEntity() {
        T entity = getEntity();
        if (entity == null) {
            return false;
        }
        EntityAndTableInfo tableInfo = DefaultLittleOrmContext.getDefaultLittleOrmContext().getEntityAndTableInfo(entity.getClass());
        if (tableInfo == null) {
            return false;
        }
        if (tableInfo.getProperties().stream().anyMatch(e -> fieldStrategyMatch(entity, e))) {
            return true;
        }
        return Objects.nonNull(tableInfo.getPrimaryKey()) ? Objects.nonNull(MetaDataOperator.getProperValue(entity, tableInfo.getPrimaryKey().getPropertyName())) : false;
    }

    /**
     * 根据实体FieldStrategy属性来决定判断逻辑
     */
    private boolean fieldStrategyMatch(T entity, PropertyAndColumnInfo e) {
       Object value = MetaDataOperator.getProperValue(entity, e.getPropertyName());
        switch (e.getWhereStrategy()) {
            case IGNORED:
                return true;
            case NOT_EMPTY:
                return Objects.nonNull(value) && StringUtils.hasLength(value.toString());
            case NEVER:
                return false;
            default:
                return Objects.nonNull(value);
        }
    }

    /**
     * 深层实体判断属性
     *
     * @return true 为空
     */
    public boolean isEmptyOfEntity() {
        return !nonEmptyOfEntity();
    }

    /**
     * 获取格式化后的执行sql
     *
     * @return sql
     * @since 3.3.1
     */
    public String getTargetSql() {
        return getSqlSegment().replaceAll("#\\{.+?}", "?");
    }

    /**
     * 条件清空
     *
     * @since 3.3.1
     */
    abstract public void clear();
}
